package com.starblink.android.basic.guide

import com.starblink.android.basic.config.GuangConfig
import com.starblink.android.basic.ext.toastShowDev
import com.starblink.android.basic.guide.bean.GuideSceneEntry
import com.starblink.android.basic.guide.bean.SkGuideEnum
import com.starblink.android.basic.network.base.BaseSiteSwitch
import com.starblink.android.basic.sensorsdata.spm.impl.SpmTrackHandler
import com.starblink.android.basic.user.UserDataCenter
import com.starblink.android.basic.util.bus.FlowConst
import com.starblink.basic.route.RoutePage
import com.starblink.basic.storage.SkStorage
import com.starblink.basic.util.ActivityStackManage
import com.starblink.basic.util.log.YYLogUtils
import java.util.*

object SkNoviceManage {

    private var guideScenesEntrySet = hashMapOf<SkGuideEnum, GuideSceneEntry>()

    //当前需要加载的所有场景集合对应场景的优先级集合 已排序的
    private var scenesSortList = mutableListOf<GuideSceneEntry>()

    // sceneName -->  Stack<GuideSceneEntry>
    private var realScenesStack = hashMapOf<String, Stack<GuideSceneEntry>>()
    private var reverseScenesStack = hashMapOf<String, Stack<GuideSceneEntry>>()
    private var showToastDev = true


    fun initVoiceGuide() {
        showToastDev = SkStorage.getBoolean(GuangConfig.DEFAULT_DETAIL_TOAST, false)
        addScenesData()
        sortAndGroup()
        //默认这个弹窗不弹
//        hasPopGuide(SkGuideEnum.SWITCH_SITE, pop = false)
    }


    /**
     * 是否存在互斥 需要跳过一些场景先弹出
     *
     * @param jump 是否跳过
     * @param jumpList 出入需要跳过的场景
     *
     */
    fun canShowGuide(
        guideType: SkGuideEnum,
        jump: Boolean = false,
        jumpList: ArrayList<SkGuideEnum> = arrayListOf()
    ): Boolean {
        //如果需要切换站点 不弹出各种引导
        if (SpmTrackHandler.siteStatusHasSwitch) {
            return false
        }

        val sceneEntry = guideScenesEntrySet[guideType]
        if (sceneEntry == null) {
            toastShowDev("此场景不存在，请检查配置", showToastDev)
            return false
        }
        //登录场景 但是没登录 不弹出
        if (sceneEntry.guideType.name.endsWith(
                "_N_L",
                ignoreCase = true
            ) && !UserDataCenter.isLogin()
        ) {
            toastShowDev("需要登录", showToastDev)
            return false
        }
        //已经弹出  禁止重复弹出
        if (sceneEntry.hasShow) {
            return false
        }
        val popStack = reverseScenesStack[sceneEntry.sceneName] ?: return false
        //判断是否应该弹出
        var show = true
        //匹配标志
        var canCompare = false
        popStack.forEach {
            YYLogUtils.e("${it.guideType.name}------->${it.hasShow}")
            if (guideType == it.guideType) {
                //匹配到就不往下执行了
                canCompare = true
                show = show && !it.hasShow
            }
            if (!canCompare) {
                //是否跳过一些前置判断 此功能为互斥场景使用
                if (jump && jumpList.contains(it.guideType)) {
                    show = show && true
                } else {
                    show = show && it.hasShow
                }
            }
        }
//        if (!show) {
//            return false
//        }
//        //判断是否真的可以弹出 ↑↑↑↑↑↑↑↑↑↑↑↑
//        return true

        return show
    }

    fun hasPopGuide(guideType: SkGuideEnum, pop: Boolean = true) {
        try {
            val sceneEntry = guideScenesEntrySet[guideType] ?: return
            sceneEntry.hasShow = true
            SkStorage.put(guideType.name, true)
            if (pop) {
                realScenesStack[sceneEntry.sceneName]?.peek()?.let {
                    reverseScenesStack[sceneEntry.sceneName]?.remove(it)
                }
                realScenesStack[sceneEntry.sceneName]?.pop()
            }
            YYLogUtils.e("${guideType.name}-111--> ${toMString(realScenesStack[sceneEntry.sceneName])}")
            YYLogUtils.e("${guideType.name}-222--> ${toMString(reverseScenesStack[sceneEntry.sceneName])}")
        } catch (e: Exception) {
            YYLogUtils.e(" 出错啦~~~~~")
            YYLogUtils.e(" 出错啦~~~~~")
        }
    }


    fun setGuideFalse(guideType: SkGuideEnum) {
        val sceneEntry = guideScenesEntrySet[guideType] ?: return
        //引用传递，set改了 list和stack一起改了
        sceneEntry.hasShow = false
        SkStorage.put(guideType.name, false)
        YYLogUtils.e("-111aaaa--> ${toMString(realScenesStack[sceneEntry.sceneName])}")
        YYLogUtils.e("-222aaaa--> ${toMString(reverseScenesStack[sceneEntry.sceneName])}")
    }

    /**
     * 初始化单个新手引导状态
     */
    private fun initSingleGuideConfig(
        guideType: SkGuideEnum,
        sceneName: String,
        firstPriority: Int, secondPriority: Int, thirdPriority: Int
    ) {
        guideScenesEntrySet[guideType] = GuideSceneEntry(
            guideType = guideType,
            sceneName = sceneName,
            firstPriority = firstPriority,
            secondPriority = secondPriority,
            thirdPriority = thirdPriority,
            hasShow = SkStorage.getBoolean(guideType.name, false)
        )
    }

    /**
     * 分组和排序 //获取和当前场景的同类场景 判断是否轮到它弹出
     */
    private fun sortAndGroup() {

        for ((_, v) in guideScenesEntrySet) {
            scenesSortList.add(v)
        }
        //判断是否真的可以弹出 ↓↓↓↓↓↓↓↓
        //重新排序 升序 防止初始化时顺序可能是错的的情况
        //相同场景下 谁优先级高 谁先出来
        //同时存在相同高等 优先级下 没数据 互斥的情况

        //排序 https://blog.csdn.net/u011068702/article/details/119939256
        scenesSortList.sortWith(
            compareBy(
                { it.firstPriority },
                { it.secondPriority },
                { it.thirdPriority })
        )


        for (v in scenesSortList) {
            if (reverseScenesStack[v.sceneName] == null) {
                reverseScenesStack[v.sceneName] = Stack()
            }
            if (!v.hasShow) {
                reverseScenesStack[v.sceneName]!!.push(v)
            }
        }

        YYLogUtils.e("${toListString("前")}")
        //因为升序入栈 所以要反转一下
        scenesSortList.reverse()
        YYLogUtils.e("${toListString("后")}")
        //相同场景的入栈
        for (v in scenesSortList) {
            if (realScenesStack[v.sceneName] == null) {
                realScenesStack[v.sceneName] = Stack()
            }
            if (!v.hasShow) {
                realScenesStack[v.sceneName]!!.push(v)
//                YYLogUtils.e("${toMString(realScenesStack[v.sceneName])}")
            }
        }


    }


    private fun toMString(s: Stack<GuideSceneEntry>?): String {

        val res = StringBuilder("Stack:")
        res.append("Stack：").append("[")
        if (!s.isNullOrEmpty()) {
            s.forEach {
                res.append("Stack ${it.guideType}--${it.firstPriority}--${it.secondPriority}----${it.hasShow},")
            }
            res.deleteCharAt(res.length - 1)
        }
        res.append("] top ")
        return res.toString()
    }

    private fun toListString(tag: String): String {

        val res = StringBuilder("Stack:")
        res.append("Stack：").append("[")
        scenesSortList?.forEach {
            res.append("toListString $tag ${it.guideType}--${it.firstPriority}--${it.secondPriority}----${it.hasShow},")
        }
        res.deleteCharAt(res.length - 1)
        res.append("] top ")
        return res.toString()
    }


    /**
     * 清除所有状态
     */
    fun resetVoiceGuide(reset: Boolean = true) {
        if (reset) {
            for ((key, value) in guideScenesEntrySet) {
                value.hasShow = false
                SkStorage.put(value.guideType.name, false)
            }
        }
        guideScenesEntrySet.clear()
        scenesSortList.clear()
        realScenesStack.clear()
        reverseScenesStack.clear()
        initVoiceGuide()
    }

    /**
     * 重置单个引导的状态
     */
    fun resetSingleGuide(type: SkGuideEnum) {
        SkStorage.put(type.name, false)
        guideScenesEntrySet.clear()
        scenesSortList.clear()
        realScenesStack.clear()
        reverseScenesStack.clear()
        initVoiceGuide()
    }

    private fun addScenesData() {
        initSingleGuideConfig(
            guideType = SkGuideEnum.HOME_FRG_NOTIFY_PERMISSION_V2,
            sceneName = RoutePage.Main.HOME_FRAGMENT,
            firstPriority = 101,
            secondPriority = 1,
            thirdPriority = 0
        )
        initSingleGuideConfig(
            guideType = SkGuideEnum.HOME_FRG_DISCOUNT_V2,
            sceneName = RoutePage.Main.HOME_FRAGMENT,
            firstPriority = 101,
            secondPriority = 2,
            thirdPriority = 0
        )
        initSingleGuideConfig(
            guideType = SkGuideEnum.HOME_FRG_BRAND_V2,
            sceneName = RoutePage.Main.HOME_FRAGMENT,
            firstPriority = 101,
            secondPriority = 3,
            thirdPriority = 0
        )


        initSingleGuideConfig(
            guideType = SkGuideEnum.HOME_ADVERT_DIALOG,
            sceneName = RoutePage.Main.HOME_FRAGMENT,
            firstPriority = 101,
            secondPriority = 5,
            thirdPriority = 0
        )

        initSingleGuideConfig(
            guideType = SkGuideEnum.HOME_FRG_1_PRODUCT_COLL_V2,
            sceneName = "ProductFindSimilarPopView",
            firstPriority = 201,
            secondPriority = 1,
            thirdPriority = 0
        )
//        initSingleGuideConfig(
//            guideType = SkGuideEnum.HOME_FRG_2_PRODUCT_V2,
//            sceneName = "ProductFindSimilarPopView",
//            firstPriority = 201,
//            secondPriority = 2,
//            thirdPriority = 0
//        )
        initSingleGuideConfig(
            guideType = SkGuideEnum.BRAND_DETAIL_BRAND_FOLLOW,
            sceneName = "BrandDetailActivity",
            firstPriority = 301,
            secondPriority = 1,
            thirdPriority = 0
        )

        initSingleGuideConfig(
            guideType = SkGuideEnum.IMG_SEARCH_GUIDE_1_13,
            sceneName = RoutePage.ImageSearch.PAGE_CAMERA,
            firstPriority = 106,
            secondPriority = 0,
            thirdPriority = 0
        )
    }


    /**
     * @param  sceneEnum
     * @param  popIsShow 是否弹出引导后 立即消费这个引导 将此引导是否弹窗的状态置为已弹出
     * @param  nextAction 可以弹出引导 执行下一步 如弹出引导弹窗
     *
     */
    inline fun whetherGuideCanBeDisplayed(
        sceneEnum: SkGuideEnum,
        oncePopSetFalse: Boolean = true,
        crossinline canPop: () -> Unit,
        crossinline hasPop: () -> Unit,
    ) {
        if (canShowGuide(sceneEnum)) {
            if (oncePopSetFalse) {
                hasPopGuide(sceneEnum)
            }
            canPop()
        } else {
            hasPop()
        }
    }


}